package com.koron.configure.workflow.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageInfo;
import com.koron.bean.app.AppBean;
import com.koron.bean.base.BaseBean;
import com.koron.bean.query.PageQuery;
import com.koron.common.core.business.common.mapper.SystemCommonMapper;
import com.koron.common.core.business.workflow.bean.po.ConfigureWorkflow;
import com.koron.common.core.business.workflow.bean.po.ConfigureWorkflowPlugin;
import com.koron.common.core.business.workflow.bean.po.ConfigureWorkflowStaff;
import com.koron.common.core.business.workflow.bean.properties.WorkflowPlugin;
import com.koron.common.core.business.workflow.bean.result.DefineResult;
import com.koron.common.core.business.workflow.templates.WorkFlowHandler;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.StringUtils;
import com.koron.configure.workflow.bean.dto.ConfigureWorkflowDTO;
import com.koron.configure.workflow.bean.dto.ConfigureWorkflowNodeDTO;
import com.koron.configure.workflow.bean.dto.ConfigureWorkflowPluginDTO;
import com.koron.configure.workflow.mapper.ConfigureWorkflowMapper;
import com.koron.configure.workflow.service.ConfigureWorkflowPluginService;
import com.koron.configure.workflow.service.ConfigureWorkflowService;
import com.koron.configure.workflow.service.ConfigureWorkflowStaffService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 业务配置管理-流程配置(ConfigureWorkflow)表服务实现类
 *
 * @author jzp
 * @since 2022-01-11 11:35:49
 */
@Service
@RequiredArgsConstructor
public class ConfigureWorkflowServiceImpl implements ConfigureWorkflowService {
    private final WorkFlowHandler workFlowHandler;
    private final ConfigureWorkflowPluginService configureWorkflowPluginService;
    private final ConfigureWorkflowStaffService configureWorkflowStaffService;

    /**
     * 通过ID查询单条数据
     */
    @Override
    @TaskAnnotation("getById")
    public ConfigureWorkflow getById(SessionFactory factory, String id) {
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        return mapper.selectById(id);
    }

    /**
     * 通过ID查询单条数据
     */
    @Override
    @TaskAnnotation("getDtoById")
    public ConfigureWorkflowDTO getDtoById(SessionFactory factory, String id) {
        // 1. 获取主表数据
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        ConfigureWorkflow configureWorkflow = mapper.selectById(id);
        ConfigureWorkflowDTO configureWorkflowDTO = BeanUtil.toBean(configureWorkflow, ConfigureWorkflowDTO.class);

        // 2. 获取工作流节点信息
        List<DefineResult> define = workFlowHandler.define(configureWorkflowDTO.baseParam(), null);

        // 3. 获取插件信息
        List<ConfigureWorkflowPluginDTO> configureWorkflowPluginDTOS = configureWorkflowPluginService.listDtoByWorkflowId(factory, id);

        // 5. 设置最终返回的节点配置信息
        List<ConfigureWorkflowNodeDTO> configureWorkflowNodeDTOList = new ArrayList<>();
        for (DefineResult defineResult : define) {
            // 节点基本信息
            ConfigureWorkflowNodeDTO configureWorkflowNodeDTO = new ConfigureWorkflowNodeDTO();
            configureWorkflowNodeDTO.setNodeId(defineResult.getNodeId());
            configureWorkflowNodeDTO.setNodeCode(defineResult.getNodeCode());
            configureWorkflowNodeDTO.setNodeName(defineResult.getNodeName());

            // 设置当前节点的插件信息
            Optional.ofNullable(configureWorkflowPluginDTOS).ifPresent(a -> {
                // 找到当前节点的插件信息
                Map<Integer, ConfigureWorkflowPluginDTO> map = a.stream()
                        .filter(e -> StrUtil.equals(defineResult.getNodeId(), e.getNodeId()))
                        .collect(Collectors.toMap(ConfigureWorkflowPluginDTO::getType, e -> e, (o1, o2) -> o1));

                // 自动填充其他的规则
                List<ConfigureWorkflowPluginDTO> collect = Stream.of(0, 1, 2).map(type -> {
                    ConfigureWorkflowPluginDTO configureWorkflowPluginDTO;
                    if (!map.containsKey(type)) {
                        configureWorkflowPluginDTO = new ConfigureWorkflowPluginDTO();
                        configureWorkflowPluginDTO.setType(type);
                        configureWorkflowPluginDTO.setEnabled(0);
                    } else {
                        configureWorkflowPluginDTO = map.get(type);
                    }
                    return configureWorkflowPluginDTO;
                }).collect(Collectors.toList());

                configureWorkflowNodeDTO.setConfigureWorkflowPluginDTOList(collect);
            });
            configureWorkflowNodeDTOList.add(configureWorkflowNodeDTO);
        }
        configureWorkflowDTO.setConfigureWorkflowNodeDTOList(configureWorkflowNodeDTOList);
        return configureWorkflowDTO;
    }

    @Override
    @TaskAnnotation("getWorkflow")
    public ConfigureWorkflow getWorkflow(SessionFactory factory, String processCode){
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        return mapper.selectOneWorkflow(processCode);
    }

    /**
     * 获取开启的插件
     */
    @Override
    @TaskAnnotation("getValidPlugin")
    public WorkflowPlugin getValidPlugin(SessionFactory factory, String processCode, String nodeCode, Integer type) {
        // 查询工作流模板信息
        ConfigureWorkflow workflow = getWorkflow(factory, processCode);
        if (workflow == null) {
            return null;
        }
        WorkflowPlugin workflowPlugin = BeanUtil.toBean(workflow, WorkflowPlugin.class);

        // 查询插件信息
        ConfigureWorkflowPlugin configureWorkflowPlugin = new ConfigureWorkflowPlugin();
        configureWorkflowPlugin.setWorkflowId(workflowPlugin.getId());
        configureWorkflowPlugin.setNodeCode(nodeCode);
        configureWorkflowPlugin.setType(type);
        configureWorkflowPlugin.setEnabled(1);
        List<ConfigureWorkflowPluginDTO> configureWorkflowPluginDTOS = configureWorkflowPluginService.listDto(factory, configureWorkflowPlugin);
        if (CollectionUtils.isEmpty(configureWorkflowPluginDTOS)) {
            return workflowPlugin;
        }
        Assert.state(configureWorkflowPluginDTOS.size() == 1, "查询到该节点有多个插件，请正确配置");
        ConfigureWorkflowPluginDTO configureWorkflowPluginDTO = configureWorkflowPluginDTOS.get(0);
        workflowPlugin.setConfigureWorkflowPlugin(configureWorkflowPluginDTO);
        if (CollectionUtils.isEmpty(configureWorkflowPluginDTO.getConfigureWorkflowStaffList())) {
            return workflowPlugin;
        }
        workflowPlugin.setConfigureWorkflowStaffList(configureWorkflowPluginDTO.getConfigureWorkflowStaffList());
        return workflowPlugin;
    }

    /**
     * 查询所有数据
     */
    @Override
    @TaskAnnotation("list")
    public List<ConfigureWorkflow> list(SessionFactory factory, ConfigureWorkflow configureWorkflow) {
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        return mapper.selectList(configureWorkflow);
    }

    @Override
    @TaskAnnotation("page")
    public PageInfo<ConfigureWorkflow> page(SessionFactory factory, PageQuery pageQuery, ConfigureWorkflow configureWorkflow) {
        return ConfigureWorkflowService.super.page(factory, pageQuery, configureWorkflow);
    }

    /**
     * 新增数据
     */
    @Override
    @TaskAnnotation("save")
    public boolean save(SessionFactory factory, ConfigureWorkflow configureWorkflow) {
        // 重复信息检查
        String errorMsg = checkDuplicateWorkflow(factory, configureWorkflow);
        if (errorMsg != null) {
            throw new IllegalArgumentException(errorMsg);
        }
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        return mapper.insertOrUpdate(configureWorkflow) > 0;
    }

    @Override
    @TaskAnnotation("saveBatch")
    public boolean saveBatch(SessionFactory factory, List<ConfigureWorkflow> configureWorkflowList) {
        if (CollectionUtils.isEmpty(configureWorkflowList)) {
            return false;
        }
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        return mapper.insertOrUpdateBatch(configureWorkflowList) > 0;
    }

    @Override
    @TaskAnnotation("saveDto")
    public boolean saveDto(SessionFactory factory, ConfigureWorkflowDTO configureWorkflowDTO) {

        // 1. 保存基本信息
        save(factory, configureWorkflowDTO);

        // 2. 设置节点配置信息
        if (CollectionUtils.isEmpty(configureWorkflowDTO.getConfigureWorkflowNodeDTOList())) {
            return true;
        }
        // 声明两个list对象，用于存储入库的数据
        List<ConfigureWorkflowPlugin> configureWorkflowPluginLists = new ArrayList<>();
        List<ConfigureWorkflowStaff> configureWorkflowStaffLists = new ArrayList<>();

        // 所有节点列表
        List<ConfigureWorkflowNodeDTO> configureWorkflowNodeDTOList = configureWorkflowDTO.getConfigureWorkflowNodeDTOList();
        for (ConfigureWorkflowNodeDTO configureWorkflowNodeDTO : configureWorkflowNodeDTOList) {
            // 当前节点的插件列表，三个以下且type不重复
            List<ConfigureWorkflowPluginDTO> configureWorkflowPluginDTOList = configureWorkflowNodeDTO.getConfigureWorkflowPluginDTOList();
            if (!CollectionUtils.isEmpty(configureWorkflowPluginDTOList)) {
                // 断言三个以下且type不重复
                for (ConfigureWorkflowPluginDTO e : configureWorkflowPluginDTOList) {
                    e.setId(CodeTools.getCode32());
                    e.setNodeId(configureWorkflowNodeDTO.getNodeId());
                    e.setNodeCode(configureWorkflowNodeDTO.getNodeCode());
                    e.setWorkflowId(configureWorkflowDTO.getId());
                    if (e.getEnabled() == null) {
                        e.setEnabled(0);
                    } else if (e.getEnabled() > 0 && StringUtils.isEmpty(e.getAccessUrl())) {
                        throw new IllegalArgumentException("启用后，接口url为必填");
                    }
                    Optional.ofNullable(e.getConfigureWorkflowStaffList()).ifPresent(ll -> {
                        for (ConfigureWorkflowStaff q : ll) {
                            q.setWorkflowId(configureWorkflowDTO.getId());
                            q.setWorkflowPluginId(e.getId());
                            configureWorkflowStaffLists.add(q);
                        }
                    });
                    configureWorkflowPluginLists.add(e);
                }
            }
        }

        // 保存插件信息
        configureWorkflowPluginService.removeByWorkflowId(factory, configureWorkflowDTO.getId());
        configureWorkflowPluginService.saveBatch(factory, configureWorkflowPluginLists);

        // 保存人员信息
        configureWorkflowStaffService.removeByWorkflowId(factory, configureWorkflowDTO.getId());
        configureWorkflowStaffService.saveBatch(factory, configureWorkflowStaffLists);

        return true;
    }

    /**
     * 修改数据
     */
    @Override
    @TaskAnnotation("update")
    public boolean update(SessionFactory factory, ConfigureWorkflow configureWorkflow) {
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        return mapper.update(configureWorkflow) > 0;
    }

    /**
     * 通过主键删除数据
     */
    @Override
    @TaskAnnotation("deleteById")
    public boolean deleteById(SessionFactory factory, String id) {
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        return mapper.hidden(id) > 0;
    }

    private String checkDuplicateWorkflow(SessionFactory factory, ConfigureWorkflow configureWorkflow) {
        // 如果有id，表示更新，不用检查
        if (configureWorkflow.getId() != null) {
            return null;
        }
        ConfigureWorkflow query = new ConfigureWorkflow();
        query.setAppCode(configureWorkflow.getAppCode());
        query.setProcessCode(configureWorkflow.getProcessCode());
        List<ConfigureWorkflow> list = list(factory, query);
        // 保存数据时ProcessCode不能重复
        return list.size() > 0 ? "模板编号不能重复" : null;
    }

    @Override
    @TaskAnnotation("updateDefaultAppCode")
    public void updateDefaultAppCode(SessionFactory factory, String code) {
        ConfigureWorkflowMapper mapper = factory.getMapper(ConfigureWorkflowMapper.class);
        mapper.updateDefaultAppCode(code);
    }

    @Override
    @TaskAnnotation("copyWorkflowFromAppCode")
    public void copyWorkflowFromAppCode(SessionFactory factory, String code) {
        // 1. 当前租户的所有流程
        ConfigureWorkflow configureWorkflow = new ConfigureWorkflow();
        List<ConfigureWorkflow> list = list(factory, configureWorkflow);
        Set<String> processCodeSet = Optional.ofNullable(list).map(temp -> temp.stream().map(ConfigureWorkflow::getProcessCode).collect(Collectors.toSet())).orElse(new HashSet<>());

        // 当前数据源
        String currentDbEnv = factory.getDbEnv();
        // 当前appCode
        String currentAppCode = Objects.requireNonNull(ThreadLocalContext.getApp(), "检测不到当前数据源").getCode();

        // 查询指定租户
        factory.setDbEnv("_default");
        SystemCommonMapper mapper = factory.getMapper(SystemCommonMapper.class);
        AppBean appBean = mapper.queryAppBeanByCode(code);
        // code对应的数据源 查询code的所有数据
        factory.setDbEnv(appBean.getMark());
        List<ConfigureWorkflow> list1 = list(factory, configureWorkflow);
        List<ConfigureWorkflowPlugin> list2 = configureWorkflowPluginService.list(factory, new ConfigureWorkflowPlugin());

        // 过滤掉已有的流程，并且设置部门信息为空
        List<ConfigureWorkflow> configureWorkflowList = list1.stream()
                .filter(e -> !processCodeSet.contains(e.getProcessCode()))
                .peek(e -> {
                    e.setAppCode(currentAppCode);
                    e.setDeptId(null);
                    e.setDeptName(null);
                })
                .collect(Collectors.toList());
        // 只保存没有的流程插件
        Set<String> configureWorkflowIdList = configureWorkflowList.stream().map(BaseBean::getId).collect(Collectors.toSet());
        list2 = list2.stream().filter(e -> configureWorkflowIdList.contains(e.getWorkflowId())).collect(Collectors.toList());
        // 保存数据
        factory.setDbEnv(currentDbEnv);
        saveBatch(factory, configureWorkflowList);
        configureWorkflowPluginService.saveBatch(factory, list2);
    }

}
